home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Development Kits / MPW etc / MPW-GM / MPW / Examples / CFMExamples / ModApp / ModuleSources / Koch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-03  |  15.7 KB  |  577 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        KochTool.c
  3.  
  4.     Contains:    The main body of the "Koch Rotate" demo made into a ModApp tool
  5.  
  6.     Written by:    Richard Clark, Stuart E. Schechter, Craig Agricola
  7.  
  8.     Copyright:    © 1993-1994 by Apple Computer, Inc., all rights reserved.
  9.                 Portions Copyright © 1993 by Stuart E. Schechter and
  10.                 Craig Agricola. Used by permission.
  11.     
  12.     ****************************************************************************
  13.                                 Koch Rotate
  14.                 'an experiment in real time fractal generation'
  15.                                   1993 by
  16.                                   
  17.              by Stuart E. Schechter    -    The Ohio State University
  18.             and    Craig Agricola        -    Case Western Reserve University
  19.     
  20.     This program may be copied are modified as long as all versions containing
  21.     any of the original codes contain credit to the authors in both source code
  22.     and the running program.
  23.     
  24.     
  25.     Craig Barret Agricola                    Stuart Edward Schechter
  26.     agricocb@laird.ccds.cincinnati.oh.us    schechter.1@osu.edu
  27.     (513) 783-2684                            (513) 793-5392
  28.     6132 Osceola Rd.                        5730 Kugler Mill Rd.
  29.     Morrow, OH                                Cincinnati, OH
  30.     45152                                    45236-2040
  31.     ******************************************************************************
  32.  
  33.     Change History (most recent first):
  34.  
  35.                  2/16/94    RC        Added code in ImageSnowflake() to see if the GWorld has been
  36.                                      purged.
  37.                   7/2/93    RC        d1 release
  38.  
  39.     To Do:
  40. */
  41.  
  42.  
  43. #define abs(x) (((x)<0) ? -(x) : (x))
  44.  
  45. #ifdef THINK_C
  46.     #define ToolStartup main
  47. #endif
  48.  
  49. #ifndef __MEMORY__
  50.     #include <Memory.h>
  51. #endif
  52.  
  53. #ifndef __RESOURCES__
  54.     #include <Resources.h>
  55. #endif
  56.  
  57. #ifndef __MENUS__
  58.     #include <Menus.h>
  59. #endif
  60.  
  61. #ifndef __QUICKDRAW__
  62.     #include <Quickdraw.h>
  63. #endif
  64.  
  65. #ifndef __QDOFFSCREEN__
  66.     #include <QDOffscreen.h>
  67. #endif
  68.  
  69. #ifndef __WINDOWS__
  70.     #include <Windows.h>
  71. #endif
  72.  
  73. #include <fp.h>
  74.  
  75. #ifndef __MENUS__
  76.     #include <Menus.h>
  77. #endif
  78.  
  79. #ifndef __OSUTILS__
  80.     #include <OSUtils.h>    // For Secs2Date, used in our Idle routine
  81. #endif
  82.  
  83. #ifndef __FIXMATH__
  84.     #include <FixMath.h>    // For fixed-point math routines, used in drawing the clock face
  85. #endif
  86.  
  87. #include "GWorldTools.h"
  88. #include "ToolAPI.h"
  89. #include "ModApp.h"
  90.  
  91. // === Our private data types, enumerations, and #defines
  92.  
  93. #define NumFracts 4
  94. #define Pi 3.1415929
  95.  
  96. #define kToolMenu     2001
  97. enum {
  98.         cOneSnowflake = 1,
  99.         cTwoSnowflakes,
  100.         cThreeSnowflakes,
  101.         cFourSnowflakes,
  102.         /* ----- */
  103.         cLowDetail = 6,
  104.         cMediumDetail,
  105.         cHighDetail,
  106.         /* ----- */
  107.         cRotateColors = 10
  108.      };
  109.  
  110.  
  111. enum {
  112.     kHighDetailLimit = 2,
  113.     kMediumDetailLimit = 6,
  114.     kLowDetailLimit = 10
  115. };
  116.  
  117.  
  118. struct ToolPrivateData {
  119.     GWorldPtr        buffer;
  120.     Point            centerPt;                // The center of our window
  121.     int16            Radii[NumFracts];
  122.     int16            Increment[NumFracts];
  123.     int16            numSnowflakes;
  124.     int16            detailCutoff;            /* How close should 2 points be before we stop recursing? */
  125.     Boolean            rotateColors;            /* Should we animate the colors when drawing? */
  126.     Point             X_Point[NumFracts],
  127.                     Y_Point[NumFracts],
  128.                     Z_Point[NumFracts];
  129.     double_t         X_degree[NumFracts],
  130.                     Y_degree[NumFracts],
  131.                     Z_degree[NumFracts];
  132.     
  133.     RGBColor        CurrentColor;
  134. };
  135.  
  136. typedef struct ToolPrivateData ToolData, *ToolDataPtr;
  137.  
  138. // === Local prototypes
  139. static void CalculateXYZ (int Which, ToolDataPtr privateData);
  140. static void DrawKochTriangle (int Which, ToolDataPtr privateData);
  141. static void RecurKoch (int Level, Point From, Point To, ToolDataPtr privateData);
  142. static void SizeSnowflake (WindowPtr wp);
  143. static void RotateSnowflake (WindowPtr wp);
  144. static void ImageSnowflake (WindowPtr wp);
  145. static void CopySnowflake (WindowPtr wp);
  146.  
  147. // === Public routines
  148.  
  149. OSErr ToolStartup (WindowPtr wp)
  150. {
  151.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  152.     OSErr                err = noErr;
  153.     ToolDataPtr            privateData = NULL;
  154.     Rect                globalBounds;
  155.     MenuHandle            privateMenu;
  156.     short                refNum;
  157.     
  158.     // Don't bother adding anything to the tool window's block, as we don't have any private info
  159.     aWindow->toolRoutines.shutdownProc = ToolShutdown;
  160.     aWindow->toolRoutines.menuAdjustProc = ToolMenuAdjust;
  161.     aWindow->toolRoutines.menuDispatchProc = ToolMenuDispatch;
  162.     aWindow->toolRoutines.toolIdleProc = ToolIdle;
  163.     aWindow->toolRoutines.toolUpdateProc = ToolUpdate;
  164.     aWindow->toolRoutines.toolClickProc = ToolWindowClick;
  165.     aWindow->toolRoutines.toolWindowMovedProc = ToolWindowMoved;
  166.     aWindow->toolRoutines.toolWindowResizedProc = ToolWindowResized;
  167.     aWindow->toolRoutines.toolWindowActivateProc = ToolWindowActivate;
  168.  
  169.     // Allocate our private storage
  170.     privateData = (ToolDataPtr)NewPtrClear(sizeof(ToolData));
  171.     err = MemError();
  172.     if (err) goto error;
  173.  
  174.     // Allocate an offscreen buffer
  175.     globalBounds = GetGlobalBounds(wp);
  176.     err = AllocateBuffer (wp, globalBounds, &privateData->buffer, false);
  177. //    if (err) goto error; // Don't fail if we can't get the buffer
  178.     
  179.     // Set other local variables
  180.     privateData->X_degree[0] = 0;
  181.     privateData->Y_degree[0] = (2 * Pi) / 3;
  182.     privateData->Z_degree[0] = (4 * Pi) / 3;
  183.     
  184.     privateData->X_degree[1] = 0;
  185.     privateData->Y_degree[1] = (2 * Pi) / 3;
  186.     privateData->Z_degree[1] = (4 * Pi) / 3;
  187.     
  188.     privateData->X_degree[2] = 0;
  189.     privateData->Y_degree[2] = (2 * Pi) / 3;
  190.     privateData->Z_degree[2] = (4 * Pi) / 3;
  191.     
  192.     privateData->X_degree[3] = 0;
  193.     privateData->Y_degree[3] = (2 * Pi) / 3;
  194.     privateData->Z_degree[3] = (4 * Pi) / 3;
  195.             
  196.     privateData->numSnowflakes = 3;
  197.     privateData->detailCutoff = kMediumDetailLimit;
  198.     privateData->rotateColors = true;
  199.     
  200.     privateData->CurrentColor.red = 0x4400;
  201.     privateData->CurrentColor.green = 0x8008;
  202.     privateData->CurrentColor.blue = 0x2020;
  203.     SizeSnowflake(wp);
  204.  
  205.     privateData->centerPt.h = (wp->portRect.left + wp->portRect.right) / 2;
  206.     privateData->centerPt.v = (wp->portRect.top + wp->portRect.bottom) / 2;
  207.     
  208.     // Add our menu
  209.     refNum = FSpOpenResFile(&aWindow->toolSpec, fsCurPerm);
  210.     err = ResError();
  211.     if (err) goto error;
  212.     privateMenu = GetMenu(kToolMenu);
  213.     DetachResource((Handle)privateMenu);
  214.     InsertMenu(privateMenu, 0);
  215.     DrawMenuBar();
  216.     CloseResFile(refNum);
  217.     
  218.     goto noError;
  219.  
  220. error:
  221.     if (privateData) {
  222.         if (privateData->buffer)
  223.             DisposeBuffer(&privateData->buffer);
  224.         DisposePtr((Ptr)privateData);
  225.     }
  226.     return err;
  227.  
  228. noError:
  229.     aWindow->toolRefCon = (long)privateData;
  230.     return noErr;
  231. }
  232.  
  233.  
  234. void ToolShutdown (WindowPtr wp)
  235. {
  236.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  237.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  238.     
  239.     if (privateData) {
  240.         if (privateData->buffer)
  241.             DisposeBuffer(&privateData->buffer);
  242.         DisposePtr((Ptr)privateData);
  243.     }
  244.  
  245. }
  246.  
  247.  
  248. void ToolMenuAdjust (WindowPtr wp)
  249. {
  250.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  251.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  252.     MenuHandle            toolMenu = GetMenuHandle(kToolMenu);
  253.         
  254.     CheckItem(toolMenu, cOneSnowflake, privateData->numSnowflakes == 1);
  255.     CheckItem(toolMenu, cTwoSnowflakes, privateData->numSnowflakes == 2);
  256.     CheckItem(toolMenu, cThreeSnowflakes, privateData->numSnowflakes == 3);
  257.     CheckItem(toolMenu, cFourSnowflakes, privateData->numSnowflakes == 4);
  258.     CheckItem(toolMenu, cLowDetail, privateData->detailCutoff == kLowDetailLimit);
  259.     CheckItem(toolMenu, cMediumDetail, privateData->detailCutoff == kMediumDetailLimit);
  260.     CheckItem(toolMenu, cHighDetail, privateData->detailCutoff == kHighDetailLimit);
  261.     CheckItem(toolMenu, cRotateColors, privateData->rotateColors);
  262. }
  263.  
  264.  
  265. void ToolMenuDispatch (WindowPtr wp, short menuID, short itemID)
  266. {
  267.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  268.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  269.  
  270.     if (menuID == kToolMenu) {
  271.         switch (itemID) {
  272.             case cOneSnowflake:
  273.             case cTwoSnowflakes:
  274.             case cThreeSnowflakes:
  275.             case cFourSnowflakes:
  276.                 privateData->numSnowflakes = (itemID - cOneSnowflake) + 1;
  277.             break;
  278.             
  279.             case cLowDetail:
  280.                 privateData->detailCutoff = kLowDetailLimit;
  281.             break;
  282.             
  283.             case cMediumDetail:
  284.                 privateData->detailCutoff = kMediumDetailLimit;
  285.             break;
  286.             
  287.             case cHighDetail:
  288.                 privateData->detailCutoff = kHighDetailLimit;
  289.             break;
  290.             
  291.             case cRotateColors:
  292.                 privateData->rotateColors = !privateData->rotateColors;
  293.             break;
  294.         }
  295.         ToolMenuAdjust (wp);
  296.     }
  297. }
  298.  
  299.  
  300. void ToolIdle (WindowPtr wp)
  301. {
  302.     SetPort(wp);
  303.     RotateSnowflake(wp);
  304.     ImageSnowflake(wp);
  305. }
  306.  
  307.  
  308. void ToolUpdate (WindowPtr wp)
  309. {
  310.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  311.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  312.     OSErr                err;
  313.     
  314.     SetPort(wp);
  315.     if (privateData->buffer) {
  316.         err = CopyBufferToWindow (wp, privateData->buffer);
  317.         if (err)
  318.             // Something went wrong with the buffer, so use our idle routine to redraw the
  319.             // window
  320.             ImageSnowflake(wp);
  321.     } else {
  322.         ImageSnowflake(wp);
  323.     }
  324. }
  325.  
  326.  
  327. void ToolWindowClick(WindowPtr wp, EventRecord *theEvent)
  328. {
  329.     // Do nothing!
  330.     #pragma unused(wp, theEvent)
  331. }
  332.  
  333.  
  334. void ToolWindowMoved(WindowPtr wp)
  335. {
  336.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  337.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  338.  
  339.     (void)UpdateBuffer(wp, &privateData->buffer);
  340.     ToolIdle(wp);
  341. }
  342.  
  343.  
  344. void ToolWindowResized(WindowPtr wp)
  345. // Update the offscreen gWorld and our local bounds rect to match the
  346. // new window size.
  347. {
  348.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  349.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  350.     OSErr                err;
  351.     Rect                globalBounds;
  352.     
  353.     // Calculate the new body rect
  354.     privateData->centerPt.h = (wp->portRect.left + wp->portRect.right) / 2;
  355.     privateData->centerPt.v = (wp->portRect.top + wp->portRect.bottom) / 2;
  356.  
  357.     // Create the new off-screen buffer
  358.     globalBounds = GetGlobalBounds(wp);
  359.     err = AllocateBuffer (wp, globalBounds, &privateData->buffer, true); // Delete the old buffer & create a new one
  360.     // Force a redraw
  361.     SetPort(wp);
  362.     InvalRect(&wp->portRect);
  363.     ToolUpdate(wp);
  364. }
  365.  
  366.  
  367. void ToolWindowActivate(WindowPtr wp, Boolean activeFlag)
  368. {
  369.     // Nothing special to do
  370.     #pragma unused(wp, activeFlag)
  371. }
  372.  
  373.  
  374. // === Private routines
  375.  
  376.  
  377. void CalculateXYZ(int Which, ToolDataPtr privateData)
  378. {
  379.     privateData->X_Point[Which].h = privateData->centerPt.h + (int16) (privateData->Radii[Which] * cos(privateData->X_degree[Which]));
  380.     privateData->X_Point[Which].v = privateData->centerPt.h - (int16) (privateData->Radii[Which] * sin(privateData->X_degree[Which]));
  381.  
  382.     privateData->Y_Point[Which].h = privateData->centerPt.h + (int16) (privateData->Radii[Which] * cos(privateData->Y_degree[Which]));
  383.     privateData->Y_Point[Which].v = privateData->centerPt.h - (int16) (privateData->Radii[Which] * sin(privateData->Y_degree[Which]));
  384.  
  385.     privateData->Z_Point[Which].h = privateData->centerPt.h + (int16) (privateData->Radii[Which] * cos(privateData->Z_degree[Which]));
  386.     privateData->Z_Point[Which].v = privateData->centerPt.h - (int16) (privateData->Radii[Which] * sin(privateData->Z_degree[Which]));
  387. }
  388.  
  389.  
  390. void SizeSnowflake (WindowPtr wp)
  391. {
  392.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  393.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  394.     Rect                localBounds;
  395.     int16                h, v;
  396.  
  397.     localBounds = wp->portRect;
  398.         
  399.     h = (localBounds.left + localBounds.right) >> 1;
  400.     v = (localBounds.top + localBounds.bottom) >> 1;
  401.     /* Find the smaller of the 2 values and center on that */
  402.     if (h < v)
  403.         v = h;
  404.     else
  405.         h = v;
  406.  
  407.     privateData->centerPt.h = h;
  408.     privateData->centerPt.v = v;
  409.         
  410.     privateData->Increment[0] = 1;
  411.     privateData->Radii[0] = h / 1.25;
  412.     
  413.     privateData->Increment[1] = 1;
  414.     privateData->Radii[1] = h / 3.5;
  415.     
  416.     privateData->Increment[2] = -1;
  417.     privateData->Radii[2] = h / 7.0;
  418.     
  419.     privateData->Increment[3] = -1;
  420.     privateData->Radii[3] = h;
  421.  
  422. }
  423.  
  424.  
  425. void RotateSnowflake (WindowPtr wp)
  426. {
  427.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  428.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  429.     Point                centerPt = privateData->centerPt;
  430.     
  431.     /* Calculate the new position for the snowflake */
  432.     if ( privateData->Radii[0] > centerPt.h/1.5 )
  433.         privateData->Increment[0] =-3;
  434.     else if ( privateData->Radii[0] < centerPt.h/4 )
  435.         privateData->Increment[0] = 3;
  436.     privateData->Radii[0] +=  privateData->Increment[0];
  437.     privateData->X_degree[0] += .05;
  438.     privateData->Y_degree[0] += .05;
  439.     privateData->Z_degree[0] += .05;
  440.  
  441.     if ( privateData->Radii[1] > centerPt.h/4 )
  442.         privateData->Increment[1] =-2;
  443.     else if ( privateData->Radii[1] < centerPt.h/7 )
  444.         privateData->Increment[1] = 2;
  445.     privateData->Radii[1] +=  privateData->Increment[1];
  446.     privateData->X_degree[1] += .07;
  447.     privateData->Y_degree[1] += .07;
  448.     privateData->Z_degree[1] += .07;
  449.  
  450.     if ( privateData->Radii[2] > centerPt.h/7 )
  451.         privateData->Increment[2] =-1;
  452.     else if ( privateData->Radii[2] < centerPt.h/9 )
  453.         privateData->Increment[2] = 1;
  454.     privateData->Radii[2] += privateData->Increment[2];
  455.     privateData->X_degree[2] -= .08;
  456.     privateData->Y_degree[2] -= .08;
  457.     privateData->Z_degree[2] -= .08;
  458.  
  459.     if ( privateData->Radii[3] > centerPt.h/1.1 )
  460.         privateData->Increment[3] =-2;
  461.     else if ( privateData->Radii[3] < centerPt.h )
  462.         privateData->Increment[3] = 2;
  463.     privateData->Radii[3] += privateData->Increment[3];
  464.     privateData->X_degree[3] -= .05;
  465.     privateData->Y_degree[3] -= .05;
  466.     privateData->Z_degree[3] -= .05;
  467. }
  468.  
  469.  
  470. void ImageSnowflake (WindowPtr wp)
  471. {
  472.     DrawingWindowPeek    aWindow = (DrawingWindowPeek)wp;
  473.     ToolDataPtr            privateData = (ToolDataPtr)aWindow->toolRefCon;
  474.     OSErr                bufError;
  475.     CGrafPtr            oldPort;
  476.     GDHandle            oldDevice;
  477.     int16                numSnowflakes = privateData->numSnowflakes;
  478.     GWorldFlags            oldPixState;
  479.  
  480.     if (privateData->buffer == NULL) {
  481.         SetPort(wp);
  482.     } else {
  483.         bufError = LockBuffer (privateData->buffer, &oldPixState);
  484.         // Was our buffer purged?
  485.         if (bufError == kPixelsPurged) {
  486.             // try to reallocate and lock the buffer
  487.             OSErr err2;
  488.             err2 = UpdateBuffer(wp, &privateData->buffer);
  489.             if (err2 == noErr) 
  490.                 bufError = LockBuffer (privateData->buffer, &oldPixState);
  491.         }
  492.         // An error should only happen if the buffer couldn't be locked down
  493.         // or was purged and cannot be reallocated. In that case, we'll draw
  494.         // without buffering
  495.         if (bufError == noErr) {
  496.             GetGWorld(&oldPort,&oldDevice);
  497.             SetGWorld(privateData->buffer, NULL);
  498.         }
  499.     }
  500.         
  501.     /* Image the snowflake */
  502.     EraseRect(&wp->portRect);
  503.     if (numSnowflakes == 4) {
  504.         CalculateXYZ(1, privateData);        /* Calculate triangular points for basis of Koch Snowflakes */
  505.         DrawKochTriangle(1, privateData);    /* Call function to draw the Koch Snowflake */
  506.     }
  507.     
  508.     if (numSnowflakes >= 3) {
  509.         CalculateXYZ(0, privateData);
  510.         DrawKochTriangle(0, privateData);
  511.     }
  512.     
  513.     if (numSnowflakes >= 2) {
  514.         CalculateXYZ(2, privateData);
  515.         DrawKochTriangle(2, privateData);
  516.     }
  517.  
  518.     CalculateXYZ(3, privateData);
  519.     DrawKochTriangle(3, privateData);
  520.  
  521.     // Now, take the buffered image and transfer it to the screen
  522.     if ((privateData->buffer != NULL) && (bufError == noErr)) {
  523.         UnlockBuffer(privateData->buffer, oldPixState);
  524.         SetGWorld(oldPort, oldDevice);
  525.         CopyBufferToWindow (wp, privateData->buffer);
  526.     }
  527. }
  528.  
  529.  
  530. void DrawKochTriangle(int Which, ToolDataPtr privateData)
  531. {
  532.     RecurKoch(0, privateData->X_Point[Which], privateData->Y_Point[Which], privateData);
  533.     RecurKoch(0, privateData->Y_Point[Which], privateData->Z_Point[Which], privateData);
  534.     RecurKoch(0, privateData->Z_Point[Which], privateData->X_Point[Which], privateData);
  535. }
  536.  
  537.  
  538. void    RecurKoch(int Level, Point From, Point To, ToolDataPtr privateData)
  539. {
  540.     Point    NewFrom, NewTo, NewVertex;
  541.     int16    hDif,vDif;
  542.  
  543.     hDif = To.h-From.h;
  544.     vDif = To.v - From.v;
  545.  
  546.     if ((abs(hDif) + abs(vDif)) <= privateData->detailCutoff) {
  547.             MoveTo(From.h,From.v);
  548.             LineTo(To.h,To.v);
  549.             return;
  550.     }                
  551.  
  552.     if ((Level == 3) && (privateData->rotateColors)) {
  553.         /* Change the color value by rotating it */
  554.         RGBColor    currentColor = privateData->CurrentColor;
  555.         
  556.         currentColor.red = (currentColor.red + 200) % 0x10000;
  557.         currentColor.green = (currentColor.green + 350) % 0x10000;
  558.         currentColor.blue = (currentColor.blue + 500) % 0x10000;
  559.         privateData->CurrentColor = currentColor;
  560.         RGBForeColor(¤tColor);
  561.     }
  562.  
  563.     /* Recurse down some more before drawing */
  564.  
  565.     NewFrom.h = From.h + (hDif) / 3;
  566.     NewFrom.v = From.v + (vDif) / 3;
  567.     NewTo.h = From.h + (hDif*2) / 3;
  568.     NewTo.v = From.v + (vDif*2) / 3;
  569.     NewVertex.h = ((NewFrom.h + NewTo.h) /2)  -  (vDif/3);
  570.     NewVertex.v = ((NewFrom.v + NewTo.v) /2)  +  (hDif/3);
  571.     
  572.     RecurKoch(Level + 1, From, NewFrom, privateData);
  573.     RecurKoch(Level + 1, NewFrom, NewVertex, privateData);
  574.     RecurKoch(Level + 1, NewVertex, NewTo, privateData);
  575.     RecurKoch(Level + 1, NewTo, To, privateData);
  576. }
  577.